package cn.yeziji.forum.exception.handler;

import cn.yeziji.forum.common.enums.ForumCommonStatus;
import cn.yeziji.forum.common.ForumResult;
import cn.yeziji.forum.exception.ForumException;
import cn.yeziji.forum.utils.ForumResultUtils;
import com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.sql.SQLException;
import java.sql.SQLSyntaxErrorException;
import java.util.concurrent.CompletionException;

/**
 * 自定义异常处理
 *
 * @author gzkemays
 * @since 2021/12/22 17:08
 */
@RestControllerAdvice
@Slf4j
public class ForumExceptionHandler {
  private static ImmutableMap<Class<? extends Throwable>, ForumCommonStatus> EXCEPTIONS;
  protected static ImmutableMap.Builder<Class<? extends Throwable>, ForumCommonStatus> BUILDER =
      ImmutableMap.builder();
  // 类加载时调用
  static {
    BUILDER.put(
        HttpRequestMethodNotSupportedException.class, ForumCommonStatus.HTTP_REQ_NOT_SUPPORTED);
    BUILDER.put(HttpMessageNotReadableException.class, ForumCommonStatus.DATA_ERROR);
    BUILDER.put(HttpMediaTypeNotSupportedException.class, ForumCommonStatus.REQ_ERROR_SUPPORT);
    BUILDER.put(SQLSyntaxErrorException.class, ForumCommonStatus.SQL_OPERA_ERROR);
    BUILDER.put(SQLException.class, ForumCommonStatus.SQL_ERROR);
    BUILDER.put(NullPointerException.class, ForumCommonStatus.NULL_POINTER_ERROR);
    BUILDER.put(IllegalArgumentException.class, ForumCommonStatus.ILLEGAL_ARGS_ERROR);
  }

  @ExceptionHandler(value = ForumException.class)
  public ForumResult forumException(ForumException exception) {
    log.error("错误异常信息 --> {}", exception.getMsg());
    exception.printStackTrace();
    return ForumResultUtils.exception(exception);
  }

  @ExceptionHandler(value = MethodArgumentNotValidException.class)
  public ForumResult forumException(MethodArgumentNotValidException ex) {
    log.error("错误异常信息 --> {}", ex.getMessage());
    ex.printStackTrace();
    BindingResult bindingResult = ex.getBindingResult();
    return ForumResultUtils.validate(bindingResult);
  }

  @ExceptionHandler(value = CompletionException.class)
  public ForumResult completionException(CompletionException ex) {
    log.error("异步执行异常 ", ex.getCause());
    if (ex.getCause() instanceof ForumException) {
      return ForumResultUtils.exception((ForumException) ex.getCause());
    }
    return ForumResultUtils.error();
  }

  @ExceptionHandler(value = BindException.class)
  public ForumResult forumException(BindException ex) {
    log.error("错误异常信息 --> {}", ex.getMessage());
    BindingResult bindingResult = ex.getBindingResult();
    return ForumResultUtils.validate(bindingResult);
  }

  @ExceptionHandler(value = Exception.class)
  public ForumResult exception(Exception exception) {
    log.error("错误原因信息 --> {}", String.valueOf(exception.getCause()));
    log.error("异常类信息 --> {}", exception.getClass());
    exception.printStackTrace();
    if (EXCEPTIONS == null) {
      // 构建 exceptions
      EXCEPTIONS = BUILDER.build();
    }
    ForumCommonStatus enums = EXCEPTIONS.get(exception.getClass());
    if (enums == null) {
      log.error("未知信息 --> {}", exception.getMessage());
      exception.printStackTrace();
      return ForumResult.buildByResultEnums(ForumCommonStatus.UNKNOWN_ERROR);
    } else {
      log.error("异常信息 --> {}", exception.getMessage());
      return ForumResult.buildByResultEnums(enums);
    }
  }
}
